home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1993 / MacHack 1993.toast / MacHack™ 1987-1992 / MacHack™ '87 / Source ƒ / C ƒ / SimpleDemo & LittleDemo / SimpleTools2.c < prev   
Encoding:
Text File  |  1987-04-17  |  49.6 KB  |  1,779 lines  |  [TEXT/KAHL]

  1.  
  2.  
  3. /*
  4.     Title    : SimpleTools2.c
  5.     Author    : Erik Kilk  Copyright 1985, 1987
  6.     Dates    : June 7, 1985, June 3, 1986, November 8, 1986
  7.           November 28, 1986, April 17, 1987.
  8.     
  9.     SimpleTools is a collection of routines to aid programming
  10.     simple "Macintosh looking" programs.  SimpleTools initializes
  11.     the toolbox, monitors & acts upon events, and provides generic
  12.     i/o routines for your application.  You initialize your program
  13.     by letting SimpleTools know what windows and menus you want along
  14.     with what functions SimpleTools should call when they are
  15.     selected.
  16.     
  17.     The purpose of SimpleTools is to encourage you to program those
  18.     simple programs or to pilot larger programs which you may not
  19.     do due to the enormous effort required to use the Macintosh
  20.     toolbox.  My goal was to study Inside Macintosh once to
  21.     Create SimpleTools and then be able to forget most of the usages
  22.     of the Toolbox routines.  Instead of thumbing through hundreds of
  23.     pages of Inside Macintosh just to get something up and running,
  24.     one need only remember a dozen generic calls.
  25.  
  26.     SimpleTools is very powerful, yet also very simple to use.  One
  27.     can get a program up and running with desk accessories, windows,
  28.     and menus in only a few minutes.  Advance features of SimpleTools
  29.     allow you to retrieve enough information from SimpleTools to call
  30.     any of the toolbox routines manually if need be.  
  31.     
  32.     
  33. =========================================================================
  34.  
  35.     You may use, study, copy, and freely distribute SimpleTools if:
  36.         1)  You mention "Programmed with the aid of SimpleTools
  37.             (c) Erik Kilk 1986" in your About... window of all
  38.             programs distributed free, share, or marketted.
  39.         2)  You register by sending $20 or more to:
  40.             Erik Kilk
  41.             4949 Snyder Lane, #247
  42.             Rohnert Park, CA  94928
  43.             (707) 794-2424 weekday afternoons
  44.             to encourage me to maintain and improve SimpleTools.
  45.             
  46. ==>    For a diskette including the most recent version of SimpleTools, 
  47.     several detailed examples of using SimpleTools, and a MacWrite file
  48.     describing SimpleTools and its use in more detail, send me a
  49.     diskette with enough stamps to mail it back to you.  Make sure you
  50.     have registered as stated above.
  51.         
  52.     This is 128k, MFS, HFS, old ROM, new ROM, Mac+, & TMON compatible.
  53.     This file compiles and executes with Megamax 3.0 beta and
  54.     LightSpeed 2.1.  Adjust the definition in simple.h for your
  55.     compiler.  When porting to other compilers, pay particular
  56.     attention to where the Lightspeed and Megamax code is specified
  57.     since these places are the likely problem areas.
  58.     
  59.     LIGHTSPEED NOTE:
  60.     
  61.     Drag SimpleTools out of the main segment in your project window.
  62.     You do this by dragging it below the dotted horizontal Line in the
  63.     project window.
  64.     
  65.     SimpleTools requires the MacTraps library and stringsasm.c or
  66.     strings.c.  If you load the unix library, your project will be
  67.     larger than needed (unless you need unix for your own program.)
  68.     
  69.     MEGAMAX NOTE:
  70.     
  71.     Use Megamax's convert utility to convert all Mac names to all
  72.     lower case.  If you send me suggestions and/or new code for
  73.     SimpleTools, please convert back to mixed case first.
  74.     
  75. =========================================================================
  76.     
  77.     SimpleTools provides the following functions for your application
  78.     to call.  Note that your application need not call any Toolbox
  79.     routines directly.  The entire C program (including the standard
  80.     desk accessory support):
  81.     
  82.             main ()
  83.             {
  84.                 simpletools ("Skel");
  85.                 simplequits ();
  86.                 runsimpletools ();
  87.             }
  88.             
  89.     will execute as a Macintosh program, terminating upon the user
  90.     selecting Quit.  SimpleTools includes:
  91.     
  92.         simpletools ()        - init Toolbox and SimpleTools
  93.         simplequits ()        - add Transfer & Quit menus
  94.         simpleevents ()        - process next Mac event
  95.         runsimpletools ()    - continuously process events
  96.         
  97.         menu ("File","New",new) - install a menu
  98.         window ("My Window",..)    - install a window
  99.                     
  100.         run (function)        - install a periodic function
  101.         stop (function)        - remove a periodic function
  102.         
  103.         havenewrom ()        - test for new 128k ROM
  104.         withwindow("My Window")    - set output to a window
  105.         
  106.         stgotoxy (x, y)        - set pen to text position x, y
  107.         home ()            - clear window, set pen to home
  108.         getline (deflt, dest)    - with TE editing, get a Line
  109.         prompt (question, dest)    - with dialog box & TE, get a Line
  110.         message (string)    - with dialog box, print a string
  111.         getfile ("TEXT", name)    - with list, select a filename
  112.         putfile (orig, name)    - with list, select a filename
  113.         
  114.     
  115.     A complete Macintosh Style application (including windowing and 
  116.     menus) is given in the following trivial example...
  117.     
  118.         #include <simple.h>
  119.         
  120.         char name[50];
  121.         
  122.         got_beep()        
  123.         {
  124.             SysBeep (10);
  125.         }
  126.         
  127.         got_getname()
  128.         {
  129.             char newname[50];
  130.             *newname = 0;
  131.             if (prompt ("What is your name?", newname)) {
  132.                 strcpy (name, newname);
  133.                 withwindow ("My Window");
  134.                 home();
  135.                 update();
  136.             }
  137.         }
  138.         
  139.         in_content(x, y)
  140.         int x, y;
  141.         {
  142.             MoveTo (x, y); LineTo (x, y);
  143.         }
  144.         
  145.         update()
  146.         {
  147.             char outstring[100];
  148.             stgotoxy (1, 5);
  149.             sprintf (outstring,"Hello, %s", name);
  150.             #ifndef MEGAMAX
  151.               CtoPstr (outstring);
  152.             #endif
  153.             DrawString (outstring);
  154.         }
  155.         
  156.         main ()
  157.         {
  158.             simpletools ("Sample Program");
  159.             simplequits ();
  160.             menu ("Commands", "Beep", got_beep);
  161.             menu ("Commands", "Get Name", got_getname);
  162.             strcpy (name, "World");
  163.             window ("My Window",0,0,0,0,0L,0L,update,
  164.                 in_content);
  165.             runsimpletools ();
  166.         }
  167.         
  168. =========================================================================
  169.  
  170.     ROUTINES YOUR APPLICATION MAY CALL:
  171.     
  172.     
  173.     simpleevents ()
  174.     
  175.     To be called repeatedly by your program's main routine.  In
  176.     most SimpleTools programs, your main routine will initialize
  177.     and install SimpleTools followed by an loop such as:
  178.     
  179.         for (;;) simpleevents();
  180.         
  181.     This routine handles all window changes, menu requests, and
  182.     other Macintosh events.  There is also a routine called with
  183.     runsimpletools() which does not return.  It simply performs the
  184.     above loop.  Program exit is accomplished by assigning an
  185.     exiting routine to a menu, usually this is File/Quit.
  186.         
  187.     
  188.     simpletools (about_string)
  189.     char *about_string;
  190.     
  191.     To be called once at the very beginning of your main routine.
  192.     This routine initializes all the Macintosh software managers
  193.     and installs the basic Apple, File, and Edit menus.  The 
  194.     about_string is the name of the menu Item to appear first under
  195.     the Apple menu.
  196.     
  197.     
  198.     simplequits ()
  199.     
  200.     Installs a simple File/Quit and File/Transfer menu.  You only
  201.     want to installs these if no application dependent processing
  202.     must be done when the user selects Quit or Transfer.
  203.     
  204.     
  205.     menu (name, Item, routine)
  206.     char     *name;
  207.     char     *Item;
  208.     ProcPtr    routine;
  209.     
  210.     To be called when a new menu is to be installed on the menu bar
  211.     or when the characteristics of that menu are to be modified.
  212.     Name is the name of the menu to appear on the menu bar.  Item
  213.     is the name of the Item to appear under the menu name.  Routine
  214.     is the name of the routine to be executed when the stated menu/Item
  215.     has been selected.  The characteristics of the menu may be changed
  216.     by passing one of the constants itemdisable, itemenable, itemcheck,
  217.     or itemuncheck in place of the routine.
  218.     
  219.     
  220.     window (name, xtop, ytop, xbot, ybot, act, deact, update, content)
  221.     char     *name;
  222.     int      xtop, ytop;
  223.     int      xbot, ybot;
  224.     ProcPtr    act, deact, update, content;
  225.     
  226.     To be called when a new window is to be installed on the screen
  227.     or when the characteristics of that window are to be modified.
  228.     Name is the name of the window.  Xtop, ytop, xbot, and ybot are
  229.     the initial coordinates of the new window.  Act is the name of
  230.     the procedure to execute when the window becomes the top or
  231.     active window.  Deact is the name of the procedure to execute when
  232.     the window ceases being the top window and deactivates.  Update
  233.     is the name of the procedure called when the Macintosh needs to
  234.     redraw the window's contents.  Content is the name of the procedure
  235.     called when the mouse is pressed within the window.  The procedure
  236.     specified as content will be passed an x and y integer value
  237.     representing the local mouse coordinates.
  238.     
  239.     
  240.     withwindow (name)
  241.     char *name;
  242.     
  243.     To be called when you want to select which window will receive
  244.     output and drawings.  In most cases, SimpleTools will select the
  245.     appropriate window before calling your specified act, deact,
  246.     update, or content procedures.  Use this at other times.
  247.     
  248.     
  249.     run (routine)
  250.     ProcPtr    routine;
  251.     
  252.     To be called when you want a routine to be continuously executed
  253.     once each time simpleevents() is called.  Small, quickly running
  254.     routines should be used so as not to Delay the next event
  255.     processing.  Pseudo multiprocessing with each routine running in
  256.     its own window can be accomplished by making sure a run routine
  257.     uses withwindow() to direct its output to the proper window.
  258.     
  259.     
  260.     stop (routine)
  261.     ProcPtr routine;
  262.     
  263.     To be called when you want to remove a previously run() routine
  264.     from the list of routines to run.  50 routines can fit into the
  265.     run list.
  266.     
  267.     
  268.     home ()
  269.     
  270.     Clears the current window and positions the pen such that any
  271.     following text will appear in the upper left corner of the
  272.     window.
  273.     
  274.     
  275.     stgotoxy (column, row)
  276.     int column, row;
  277.     
  278.     Positions the pen in the current window so that the next text
  279.     output will appear in text row and column.  This is compatible
  280.     with some old text only terminals.  stgotoxy (1, 1) positions the
  281.     pen in the upper left corner.  Any negative coordinate leaves
  282.     that axis of the pen where it currently is.
  283.     
  284.     
  285.     getline (default, destination)
  286.     char *default;
  287.     char *destination;
  288.     
  289.     Calling this routine begins a "modal" mode where the user is
  290.     required to enter a Line of text.  This would be similar to
  291.     using scanf() on "non-Mac", text-only terminals.  This routine
  292.     uses the Macintoshes built in Text-Edit routines allowing the
  293.     user to edit his Line until <RETURN> is pressed.  The flashing
  294.     bar Cursor is positioned at the current pen location.  The 
  295.     resulting string is placed into destination.  Default contains
  296.     the initial value to be displayed on the screen.  You may use
  297.     the null string "" for default.
  298.     
  299.     
  300.     prompt (question, answer)
  301.     char *question;
  302.     char *answer;
  303.     
  304.     This routine places a small 3-lined Macintosh Style dialog window
  305.     prompting the user with question and getting the answer in a
  306.     boxed Text-Edit area.  Two buttons are displayed to terminate the
  307.     user entry.  If Cancel is clicked upon, FALSE is returned.  If
  308.     okay is clicked upon, TRUE is returned.  Answer must be set to
  309.     a default value, "" is okay.
  310.     
  311.     
  312.     message (message)
  313.     char *message;
  314.     
  315.     This routine is similar to prompt except no textual response is
  316.     asked from the user.  This is like an Alert dialog.  Just like
  317.     prompt, TRUE or FALSE is returned depending upon which Button the
  318.     user presses.
  319.     
  320.     
  321.     getfile (file_type, reply)
  322.     char *file_type;
  323.     char *replay;
  324.     
  325.     This routine places the standard Macintosh SFGetFile() window
  326.     up with a list of files of file_type.  Once the user selects a
  327.     file, the answer is returned in the string reply.  Also, and
  328.     very important for HFS, the working volume/folder is set so that
  329.     any subsequent open() with reply as the file name will open the
  330.     correct selected file.  The open() should be done before someone
  331.     has a chance to change the working volume.  This routine will 
  332.     return FALSE if the user selects the CANCEL Button.
  333.     
  334.     
  335.     putfile (origname, reply)
  336.     char *origname;
  337.     char *reply;
  338.     
  339.     This routine is like getfile, except the standard putfile window
  340.     is displayed with origname as the default name to save a file as.
  341.     The actual name selected by the user is returned in reply.  As
  342.     getfile, the working volume/folder is set properly for the next
  343.     open() call.
  344.  
  345. =========================================================================
  346.  
  347.     THE FOLLOWING IS THE FILE simple.h.  YOU SHOULD COPY THIS PORTION
  348.     INTO A NEW FILE NAMED simple.h SO YOU CAN #include IT INTO YOUR
  349.     SOURCE FILES.
  350.     
  351. =========================================================================
  352.  
  353. #define LIGHTSPEED    {define either LIGHTSPEED or MEGAMAX or your own}
  354.  
  355. #include <stdio.h>
  356.  
  357. #ifdef MEGAMAX
  358.   #include <menu.h>
  359.   #include <win.h>
  360. #endif
  361.  
  362. #ifdef LIGHTSPEED
  363.   #include <MenuMgr.h>
  364.   #include <WindowMgr.h>
  365. #endif
  366.  
  367. #define itemdisable    0L        
  368. #define itemenable    1L
  369. #define itemcheck    2L
  370. #define itemuncheck    3L
  371.  
  372. extern char         applestring[];
  373. extern WindowPtr     windowpoint();
  374. extern MenuHandle     mhand();
  375. extern int         windmenu;
  376. extern int         dogoaway;        
  377. extern int         wprocid;        
  378. extern int        show_new_window;
  379. extern int         sizeredraw;
  380. extern int        getlinecaps;
  381. extern ProcPtr         keydownproc;
  382. extern ProcPtr         autokeyproc;
  383. extern void        home();
  384. extern void        stnop();
  385. =========================================================================
  386.  
  387.         Here begins SimpleTools.c
  388.         _________________________
  389. */
  390.  
  391. #include "simple.h"            /* define compiler in here    */
  392.  
  393. #ifdef MEGAMAX                            
  394.         overlay "simpletools"        /* compiler dependent        */
  395.  
  396.     #include <mem.h>
  397.     #include <qd.h>
  398.     #include <qdvars.h>
  399.     #include <misc.h>
  400.     #include <event.h>
  401.     #include <res.h>
  402.     #include <win.h>
  403.     #include <dialog.h>
  404.     #include <menu.h>
  405.     #include <string.h>
  406.     #include <stdio.h>
  407.     #include <pack.h>
  408.     #include <te.h>
  409.     #include <toolbox.h>
  410.     
  411.     #define  ZZ    &
  412. #else
  413.     #include <MemoryMgr.h>
  414.     #include <Quickdraw.h>
  415.     #include <EventMgr.h>
  416.     #include <ResourceMgr.h>
  417.     #include <WindowMgr.h>
  418.     #include <TextEdit.h>
  419.     #include <DialogMgr.h>
  420.     #include <MenuMgr.h>
  421.     #include <strings.h>
  422.     #include <stdio.h>
  423.     #include <PackageMgr.h>
  424.     #include <ToolboxUtil.h>
  425.     #include <StdFilePkg.h>
  426.     #include <pascal.h>
  427.     
  428.     #define  ZZ    
  429. #endif
  430.  
  431. #define TRUE (-1)        /* local definitions             */
  432. #define FALSE 0
  433. #define maxsruns 50        /* procedure table size            */
  434. #define MESSN 30        /* array size for message dialog items    */
  435. #define QUESN 40        /* array size for prompt dialog items    */
  436. #define ROM85   0x28E        /* new rom stuff             */
  437. #define NEWROM  0x7FFF
  438. #define inzoomout 8
  439. #define inzoomin  7
  440. #define zoomproc  8
  441.  
  442. typedef struct {            /* structure for an Item    */
  443.     char        itemname[40];
  444.     int        itemno;        /* Item number within menu     */
  445.     int        menuId;        /* menu id            */
  446.     MenuHandle    menuhand;    /* Item's menu's Handle                 */
  447.     ProcPtr        menurun;    /* procedure to run         */
  448.     Ptr        next;        /* pointer to the next Item     */
  449. } itemdatum;
  450.  
  451. typedef struct {            /* structure for a menu     */
  452.     char         menuname[20];    /* to allow reference by name     */
  453.     int         menuId;        /* menu id             */
  454.     MenuHandle    menuhand;    /* menu Handle to reference menu*/
  455.     itemdatum    **itemlist;    /* pointer to the list of items */
  456.     Ptr         next;        /* pointer to the next menu     */
  457. } menudatum;
  458.  
  459. typedef struct {            /* structure for a window     */
  460.     char        windname[80];    /* window's name and reference     */
  461.     WindowPtr    wptr;        /* window's pointer reference     */
  462.     ProcPtr    wact;            /* the activate procedure     */
  463.     ProcPtr    wdeact;            /* the deactivate procedure     */
  464.     ProcPtr    wupdate;        /* the update procedure     */
  465.     ProcPtr    wcontent;        /* the content procedure     */
  466.     Ptr        next;        /* pointer to the next window     */
  467. } winddatum;
  468.  
  469. #ifdef LIGHTSPEED
  470.   pascal Boolean     *TrackBox() = 0xA83B; 
  471.   pascal void         *ZoomWindow() = 0xA83A;
  472. #endif
  473.  
  474. WindowPtr windowpoint();
  475.  
  476. /* Local variables */
  477.  
  478. menudatum     **simplemenus;        /* Handle to menu data         */
  479. char         accname[80];        /* desk accessory name to open     */
  480. Rect         dragrect, sizerect;    /* limits for moving windows     */
  481. Rect         swholescreen;
  482. winddatum    **simplewinds;        /* Handle to window data     */
  483. int        firstwind;        /* if no windows have been made    */
  484. ProcPtr     simpleruns[maxsruns];    /* list of procedures to run     */
  485. WindowPtr    debugw;            /* window pointer for debugging */
  486. int        snewrom;
  487. int        getlinecaps = FALSE;
  488.  
  489. /************************************************************************/
  490. /* GLOBAL USER MODIFIABLE VARIABLES                     */
  491. /* These are variables that you can declare extern so that you can use    */
  492. /* them to change the SimpleTools defaults                */
  493. /************************************************************************/
  494.  
  495. /* wprocid = type of window to Create on next window() call        */
  496. /* For LightSpeed C, use a lower case d and upper case P for         */
  497. /*     DocumentProc.  Megamax conversion program does this wrong.    */
  498.  
  499. int         wprocid = documentProc;    
  500.  
  501. /* dogoaway = is the next created window to have a go-away box        */
  502.  
  503. int         dogoaway = TRUE;    
  504.  
  505. /* keydownproc = the procedure to be called when keyDown is detected    */
  506. /* autokeyproc = the procedure to be called when autoKey is detected    */
  507. /* BOTH OF THESE ARE PASSED THE EVENTRECORD SO THE KEY CAN BE FOUND    */
  508.  
  509. ProcPtr     keydownproc,
  510.           autokeyproc;         
  511.         
  512. /* applestring = a string containing the Apple for menu reference    */
  513.  
  514. char         applestring[2] 
  515.           = {'\024', '\0'};     
  516.  
  517. /* windmenu = does the next window created get a choice under the
  518.               window menu (so a closed window can be brought back    */
  519.               
  520. int         windmenu = TRUE;    
  521.  
  522. /* sizeredraw = is the window's content area erased and made
  523.                 updateable upon being resized                */
  524.                 
  525. int        sizeredraw = FALSE;    
  526.  
  527. /* show_new_window = does the created window get displayed right away
  528.         on the screen, if not, then it is hidden        */
  529.         
  530. int        show_new_window = TRUE;
  531.  
  532.  
  533. /******************************************************************/
  534. /* Dialog lists.  These were calculated by using the new resource */
  535. /* editor to make a template for a dialog and then using fedit to */
  536. /* list the hex listing of the Item list for the dialog.      */
  537. /******************************************************************/
  538.  
  539. int messd[MESSN] = {2,0,0,0x38,0xf1,0x4c,0x12d,0x402,0x4f4b,0,0,5,5,
  540.         0x36,0x12d,0x800,0,0,0x38,0xac,0x4c,0xe8,0x406,
  541.         0x4361,0x6e63,0x656c};
  542. int quesd[QUESN] = {3,0,0,0x21,0xf0,0x35,0x12c,0x402,0x4f4b,0,0,8,8,
  543.         0x28,0xe8,0x800,0,0,0x2b,8,0x4b,0xe8,0x1000,0,0,
  544.         8,0xf0,0x1c,0x12c,0x406,0x4361,0x6e63,0x656c};
  545.         
  546.         
  547. /* Local procedure */
  548.  
  549. void stnop()                /* a no op procedure for defaults */
  550. {
  551. }
  552.  
  553. char *ptoc(s)
  554. char *s;
  555. {
  556.     #ifndef MEGAMAX
  557.         return (PtoCstr(s));
  558.     #else
  559.         return (s);
  560.     #endif
  561. }
  562.  
  563. char *ctop(s)
  564. char *s;
  565. {
  566.     #ifndef MEGAMAX
  567.         return (CtoPstr(s));
  568.     #else
  569.         return (s);
  570.     #endif
  571. }
  572.  
  573. /* Given a menu name, find our data structure for it.  Return a Handle
  574.    to this structure.  This is a local procedure for SimpleTools use.
  575. */
  576.  
  577. /* local procedure */
  578.  
  579. menudatum **getourmenuhandle (name)
  580. char *name;                /* name of menu bar menu */
  581. {
  582.     menudatum **here, **temp;    /* hand to menu structure*/
  583.     here = simplemenus;
  584.  
  585.     /* find the menu name or the end of out menu list */
  586.     HLock (here);
  587.     while (strcmp(name,(**here).menuname) && (**here).next )  {
  588.         temp = here;
  589.         here = (menudatum **)(**here).next;
  590.         HUnlock (temp);
  591.         HLock (here);
  592.     }
  593.         
  594.     /* see if we found it or just the end of the list */
  595.     if (!strcmp(name,(**here).menuname)) {
  596.         HUnlock (here);
  597.         return (here);
  598.     } else {
  599.         HUnlock (here);
  600.         return ((menudatum **)0L);        
  601.     }
  602. }
  603.  
  604. /* This takes a Handle to our personal Item record and either a 
  605.    procedure name or a modifier code.  If it got a procedure name,
  606.    it sets it to the Item's procedure to run when the Item is chosen.
  607.    If it got a modifier code, it changes the state of the menu's Item
  608.    to checked, unchecked, enabled, or disabled.  It especially keeps 
  609.    track of the standard Edit menu items so we can restore them after
  610.    a desk accessory is finished.
  611. */
  612.  
  613. /* Local procedure */
  614.  
  615. setitems ( items, routine)    /* set a menu Item's routine or display */
  616. itemdatum    **items;    /* if items is neg, then whole menu     */
  617. ProcPtr    routine;
  618. {
  619.     int            inumber;
  620.     MenuHandle        mhand;
  621.     
  622.     /* check to see if a procedure pointer was given to us */
  623.     if ( (((long)items)>0L) && (routine > (ProcPtr)0x1000L)) {  
  624.                         /* good procedure value */
  625.         (**items).menurun = routine;
  626.         return;
  627.     }
  628.     
  629.     /* Calculate which Item number we are going to modify */
  630.     if ( (long)items < 0L) {        /* the whole menu     */
  631.         mhand = (MenuHandle) (0L - (long)items);
  632.         inumber = 0;
  633.     } else {                /* just one Item     */
  634.         mhand = (**items).menuhand;
  635.         inumber = (**items).itemno;
  636.     }
  637.  
  638.     /* If a NULL procedure pointer, then set to a no_op routine */
  639.     if ( (inumber > 0) && ((**items).menurun == (ProcPtr)0L) )
  640.         (**items).menurun = (ProcPtr) stnop;
  641.  
  642.     /* Now change the state of a menu Item */
  643.     switch ((int)routine) {
  644.         case itemdisable: 
  645.             DisableItem(mhand,inumber); break;
  646.         case itemenable:
  647.             EnableItem(mhand, inumber); break;
  648.         case itemcheck:
  649.             CheckItem(mhand, inumber, TRUE); break;
  650.         case itemuncheck:
  651.             CheckItem(mhand, inumber, FALSE); break;
  652.     }
  653.     if (inumber == 0) DrawMenuBar();  /* if main menu was changed     */
  654.     
  655. }
  656.  
  657. /* This routine is called by the simpletools() initial routine.  It gets
  658.    the pointer list of menus started, loads the desk accessories into
  659.    the Apple menu, and loads up some standard menu entries.  The reason
  660.    menu File has a New entry, and none others, is because as this code
  661.    currently stands, a menu must have at least one Item.  And since we
  662.    want File before Edit, I had to make an entry.  The most commonly used
  663.    Item under File is Quit.  But we like quit to be at the end of the list.
  664.    So, since New is usually always first when it is used, that the one
  665.    chosen to start File.  
  666. */
  667.  
  668. /* Local procedure */
  669.  
  670. initsmenus(about)            /* init simpletools' menus */
  671. char *about;
  672. {
  673.     itemdatum **items;
  674.  
  675.     simplemenus = (menudatum **) NewHandle ( (long)sizeof(menudatum));
  676.     HLock (simplemenus);
  677.  
  678.     strcpy ( (**simplemenus).menuname, applestring);
  679.     (**simplemenus).menuId = 1;
  680.     (**simplemenus).next = (Ptr) 0L;
  681.     ctop ((**simplemenus).menuname);
  682.     (**simplemenus).menuhand = NewMenu (1, (**simplemenus).menuname);
  683.     ptoc ((**simplemenus).menuname);
  684.     HUnlock ((**simplemenus).menuhand);
  685.  
  686.     (**simplemenus).itemlist = (itemdatum **)NewHandle ( 
  687.             (long)sizeof(itemdatum));
  688.     items = (itemdatum **) (**simplemenus).itemlist;
  689.     HLock (items);
  690.  
  691.     strcpy ((**items).itemname, about);
  692.     (**items).itemno = 1;
  693.     (**items).menuId = 1;
  694.     (**items).menuhand = (**simplemenus).menuhand;
  695.     (**items).menurun = (ProcPtr) stnop;
  696.     (**items).next = 0L;
  697.     HUnlock (items);
  698.  
  699.     ctop (about);
  700.     AppendMenu ((**simplemenus).menuhand, about);
  701.     ptoc (about);
  702.     DisableItem ((**simplemenus).menuhand, 1);
  703.     menu (applestring, "-", (ProcPtr) itemdisable);
  704.     #ifdef MEGAMAX
  705.       AddResMenu ((**simplemenus).menuhand, "DRVR");
  706.     #else
  707.       AddResMenu ((**simplemenus).menuhand, 'DRVR');
  708.     #endif
  709.     InsertMenu ((**simplemenus).menuhand, 0);
  710.     HUnlock (simplemenus);
  711.  
  712.     menu ("File", "New", (ProcPtr)itemdisable);
  713.     menu ("Edit", "Undo", stnop);
  714.     menu ("Edit", "-", (ProcPtr)itemdisable);
  715.     menu ("Edit", "Cut/X", stnop);
  716.     menu ("Edit", "Copy/C", stnop);
  717.     menu ("Edit", "Paste/V", stnop);
  718.     menu ("Edit", "Clear", stnop);
  719. }
  720.  
  721. /* Local procedure */
  722.  
  723. #ifndef LIGHTSPEED
  724. gottrans () 
  725. {
  726.   char prog[80];
  727.   char *argv[3];
  728.   if ( getfile("APPL", prog) ) {
  729.     argv[1] = NULL;
  730.     execv (prog, argv);
  731.   }
  732. }
  733. #endif
  734.  
  735. /* Local procedure */
  736.  
  737. gotquit ()
  738. {
  739.   ExitToShell();
  740. }
  741.  
  742. /* This routine is for the Windows menu Item.  The Windows menu is
  743.    set up when new windows are added.  It is used to bring forward and
  744.    bring into view windows that may be under other windows or have been
  745.    sent hiding by a click on their close box.
  746. */
  747.  
  748. /* Local procedure */
  749.  
  750. showawindow(name)            /* show the named window    */
  751. char *name;
  752. {
  753.     WindowPtr foo;
  754.     foo = windowpoint(name);    /* get its window pointer    */
  755.     if ( foo ) {
  756.         ShowWindow(foo);    /* show it on the screen    */
  757.         SetPort (foo);        /* set further output to it */
  758.         if ( foo != FrontWindow())    /* if it isn't active,    */
  759.             SelectWindow (foo);    /* activate it         */
  760.     }
  761. }
  762.  
  763. /* Local procedure */
  764.  
  765. winddatum **wdatum(windpt)        /* return Handle to window data */
  766. WindowPtr windpt;
  767. {
  768.     winddatum **wind, **temp;
  769.  
  770.     if (firstwind) return ((winddatum **) 0L);
  771.     wind = simplewinds;
  772.     HLock (wind);
  773.  
  774.     while ( ((**wind).wptr != windpt) && (**wind).next) {
  775.         temp = wind;
  776.         wind = (winddatum **) (**wind).next;
  777.         HUnlock (temp);
  778.         HLock (wind);
  779.     }
  780.  
  781.     if ( (**wind).wptr == windpt) {
  782.         HUnlock (wind);
  783.         return (wind);
  784.     } else {
  785.         HUnlock (wind);
  786.         return ((winddatum **) 0L);    /* zero if not found */
  787.     }
  788. }
  789.   
  790. /* Local procedure */
  791.  
  792. runruns(event)            /* run all the installed run procedures    */
  793. EventRecord *event;        /* returns number of routines run     */
  794. {
  795.     int i=0;
  796.     WindowPtr saveport;
  797.     GetPort (&saveport);
  798.     while ( simpleruns[i] )
  799.         (*(simpleruns[i++])) (event);
  800.     SetPort (saveport);
  801.     return(i);
  802. }
  803.  
  804. /* Local procedure */
  805.  
  806. stdialog( question, answer, type)  /* a general dialog displayer     */
  807. char *question;
  808. char *answer;
  809. int  type;            /* type:  1=prompt, 2=message         */
  810. {
  811.     DialogPtr dialog;    /* dialog reference             */
  812.     Handle Item, items;    /* handles for the dialog items     */
  813.     Rect screen, box;    /* rectangles for dialog/items         */
  814.     int dtype, hit, canc;    /* Item type and which was hit         */
  815.     char tempanswer[255];    /* address where answer is         */
  816.  
  817.     items = NewHandle (512L);/* get memory for items list         */
  818.     HLock (items);        /* lock it down             */
  819.     if (type == 1)
  820.         BlockMove (quesd, *items, (long) QUESN * 2L); 
  821.     else
  822.         BlockMove (messd, *items, (long) MESSN * 2L);
  823.     SetRect (&screen, 103, 50, 409, 137);        
  824.     
  825.     /* For LIGHTSPEED, use a lower case d and upper case B and P    */
  826.     /* for DBoxProc.  Megamax conversion utility does this wrong.    */
  827.     
  828.     dialog = NewDialog (0L, &screen, "", 0, dBoxProc, -1L, 0, 0L, items);
  829.     GetDItem (dialog, 2, &dtype, &Item, &box);
  830.     ctop (question);    
  831.     SetIText (Item, question);        /* set Item#2 text     */
  832.     ptoc (question);
  833.     if (type == 1) {            /* set default answer    */
  834.         GetDItem (dialog, 3, &dtype, &Item, &box);
  835.         ctop (answer);
  836.         SetIText (Item, answer);
  837.         ptoc (answer);
  838.         canc = 4;
  839.     } else
  840.         canc = 3;
  841.     ShowWindow (dialog);            /* display the dialog    */
  842.     do {
  843.         ModalDialog (0L, &hit);        /* process the dialog    */
  844.     } while ( (hit != 1) & (hit != canc) );
  845.     if (type == 1) {
  846.         GetDItem (dialog, 3, &dtype, &Item, &box);
  847.         HLock (Item);
  848.         GetIText (Item, tempanswer);    /* get Item#3 text     */
  849.         ptoc (tempanswer);
  850.         strcpy (answer, tempanswer);    /* make a copy of it     */
  851.         HUnlock (Item);
  852.     }
  853.     HUnlock(items);                /* unlock items memory    */
  854.     HPurge(items);                /* purge it         */
  855.     DisposDialog (dialog);            /* get rid of dialog    */
  856.     return ( hit==1 );            /* return true if ok    */
  857. }  
  858.   
  859. /* Local procedures */
  860.  
  861. docommand (which, thisevent)
  862. long which;
  863. EventRecord *thisevent;
  864. {
  865.     int themenu, theitem;
  866.     long size;
  867.     char *cpoint;
  868.     GrafPtr tempport;
  869.     menudatum **here, **temp;
  870.     itemdatum **items, **tempitems;
  871.     char **myreshandle;
  872.     Handle myhandle;
  873.   
  874.     themenu = HiWord (which);
  875.     theitem = LoWord (which);
  876.     if ((themenu == 1) && (theitem != 1)) {
  877.   
  878.         /* start up a desk accessory */
  879.         HLock (simplemenus);
  880.         GetItem ((**simplemenus).menuhand, theitem, accname);
  881.         SetResLoad (FALSE);
  882.         #ifdef MEGAMAX
  883.           myreshandle = GetNamedResource ("DRVR", accname);
  884.         #else
  885.           myreshandle = GetNamedResource ('DRVR', accname);
  886.         #endif
  887.         SetResLoad (TRUE);
  888.         size = SizeResource (myreshandle);
  889.         myhandle = NewHandle ( size + 3072L);
  890.         if (myhandle == 0L) 
  891.             message ("Not enough memory to do that.");
  892.         else {
  893.             DisposHandle (myhandle);
  894.             GetPort (&tempport);
  895.             OpenDeskAcc(accname);
  896.             SetPort (tempport);
  897.         }
  898.         HUnlock (simplemenus);
  899.         return;
  900.     }
  901.     if (themenu ==3) {
  902.         /* do any system edits */
  903.         if (SystemEdit(theitem -1))  return;
  904.     }
  905.   
  906.     /* now we run an installed menu procedure */
  907.     here = simplemenus;
  908.     HLock (here);
  909.   
  910.     /* find out menu structure given the menu id */
  911.     while ( ((**here).menuId != themenu) && (**here).next) {
  912.         temp = here;
  913.         here = (menudatum **)(**here).next;
  914.         HUnlock (temp);
  915.         HLock (here);
  916.     }
  917.   
  918.     if ((**here).menuId == themenu) {
  919.   
  920.         /* now find the Item structure */
  921.         items = (**here).itemlist;
  922.         HUnlock (here);
  923.         HLock (items);
  924.  
  925.         while ( ((**items).itemno != theitem) && (**items).next) {
  926.             tempitems = items;
  927.             items = (itemdatum **)(**items).next;
  928.             HUnlock (tempitems);
  929.             HLock (items);
  930.         }
  931.   
  932.         /* prepare to give the Item name to the procedure */
  933.         cpoint = (**items).itemname;
  934.         if ((**items).itemno == theitem) 
  935.         /* if we found the Item, call its procedure */
  936.             (*((**items).menurun))(cpoint,thisevent) ;
  937.         HUnlock (items);
  938.     }
  939. }
  940.  
  941. /* Local procedure */
  942.  
  943. domousedown(thisevent)        /* respond to mouse down events */
  944. EventRecord *thisevent;        /* passed the event record */
  945. {
  946.     WindowPtr whichwindow;
  947.     int code, x, y;
  948.     char *cpoint;
  949.     menudatum **omhand;
  950.     winddatum **thewdatum;
  951.     long newplace;
  952.     Point temp;
  953.     GrafPtr saveport;
  954.  
  955.     code = FindWindow(ZZ(thisevent->where), &whichwindow);
  956.     switch (code) {
  957.         case inMenuBar:
  958.         docommand(MenuSelect(ZZ(thisevent->where)),thisevent);
  959.         break;
  960.         case inSysWindow:
  961.         SystemClick(thisevent, whichwindow); break;
  962.         case inDrag:
  963.         DragWindow(whichwindow, ZZ(thisevent->where),
  964.             &dragrect); break;
  965.         case inGrow:
  966.         newplace= GrowWindow(whichwindow, ZZ(thisevent->where),
  967.             &sizerect);
  968.         SizeWindow(whichwindow, LoWord(newplace), 
  969.         HiWord(newplace), TRUE);
  970.         if (sizeredraw) {
  971.             GetPort (&saveport);
  972.             SetPort (whichwindow);
  973.             EraseRect (&swholescreen);
  974.             InvalRect (&swholescreen);
  975.             SetPort (saveport);
  976.         }
  977.         break;
  978.         case inGoAway:
  979.         if ( TrackGoAway(whichwindow, ZZ(thisevent->where))) {
  980.             HideWindow (whichwindow);
  981.         }
  982.         break;
  983.         case inzoomout:
  984.         case inzoomin:
  985.             #ifdef MEGAMAX
  986.           if ( trackbox(whichwindow, ZZ(thisevent->where), code)) {
  987.             zoomwindow (whichwindow, code, 0);
  988.         #else
  989.           if ( TrackBox(whichwindow, ZZ(thisevent->where), code)) {
  990.             ZoomWindow (whichwindow, code, 0);
  991.         #endif
  992.             GetPort (&saveport);
  993.             SetPort (whichwindow);
  994.             EraseRect (&swholescreen);
  995.             InvalRect (&swholescreen);
  996.             SetPort (saveport);
  997.         }
  998.         break;
  999.         case inContent:
  1000.         
  1001.         /* make the window active if it isn't yet */
  1002.         if (whichwindow != FrontWindow()) {
  1003.             SelectWindow(whichwindow);
  1004.         }
  1005.   
  1006.         /* find our window data */
  1007.         thewdatum = wdatum (whichwindow);
  1008.         if (thewdatum) {
  1009.           
  1010.             /* convert the Point of click to the window's
  1011.                own coordinates since this will be always
  1012.                more useful than the global coordintates */
  1013.             temp = thisevent->where;
  1014.             SetPort (whichwindow);
  1015.             GlobalToLocal (&temp);
  1016.             #ifdef MEGAMAX
  1017.               x = temp.a.h;
  1018.               y = temp.a.v;
  1019.             #else
  1020.               x = temp.h;
  1021.               y = temp.v;
  1022.             #endif
  1023.             
  1024.             /* call the window's in content routine */
  1025.             HLock (thewdatum);
  1026.             (*((**thewdatum).wcontent))(x, y, whichwindow,
  1027.                 thisevent);
  1028.             HUnlock (thewdatum);
  1029.         }
  1030.         break;
  1031.     }
  1032. }
  1033.             
  1034.  
  1035. /************************************************************************/
  1036. /*     GLOBAL ROUTINES INTENDED TO BE USER CALLABLE PROCEDURES        */
  1037. /* THE FOLLOWING PROCEDURES HAVE BEEN WRITTEN FOR THE USER'S         */
  1038. /* APPLICATION TO CALL.                            */
  1039. /*                                     */
  1040. /************************************************************************/
  1041.  
  1042. havenewrom ()            /* returns true if new roms installed    */
  1043. {
  1044.     return ((*((int *)ROM85)) == NEWROM);
  1045. }
  1046.  
  1047. /* Menu is usually called like:
  1048.  
  1049.         menu ("File", "Print...", got_print)
  1050.         
  1051.    where the first argument is the name appearing on the menubar.  The
  1052.    2nd argument is the name appearing when the menu is pulled down.  The
  1053.    3rd argument is USUALLY the routine to be called when the user
  1054.    selects this particular menu.  Non-existant menus are created following
  1055.    the last.  The menu ordering may never be changed once created.
  1056.    Existint menus have their "routine-to-be-executed" assignment changed
  1057.    to the new routine.  If the long values 0L, 1L, 2L, or 3L are passed
  1058.    instead of a procedure, the menu characteristic is set as specified
  1059.    by the constants itemdisable, itemenable, itemcheck, itemuncheck.  For
  1060.    example:
  1061.            menu ("File", "Print...", itemdisable)
  1062.         
  1063.    PROCEDURES ASSIGNED TO MENUS ARE CALLED WITH TWO ARGUMENTS.  YOU
  1064.    DO NOT NEED TO DECLARE THESE IN YOUR PROCEDURE IF YOU DO NOT USE
  1065.    THEM.  FOR EXAMPLE, GOT_PRINT MAY BE DECLARED AS:
  1066.    
  1067.            got_print()
  1068.         char *itemname;
  1069.         EventRecord *current_event;
  1070.         {
  1071.             ...
  1072.         }
  1073.         
  1074.    Itemname is a char* pointing to the Item name.  This allows the same
  1075.    menu procedure to be used for multiple menu/Item pairs.  Maybe your
  1076.    Size menu just as items 9 Point, 10 Point, 12 Point, etc.  This way
  1077.    you can specify the same procedure for each and determine what to do
  1078.    by looking at itemname.  
  1079.    
  1080.    Current_event is a pointer to the current EventRecord that detected
  1081.    the menu selection.  You may look at this as needed.
  1082. */
  1083.    
  1084. menu (name, Item, routine)        /* install or change a menu    */
  1085. char *name;                /* the menu name         */
  1086. char *Item;                /* the Item name         */
  1087. ProcPtr routine;            /* a procedure or modifier     */
  1088. {
  1089.     menudatum **here,**temp;    /* a roving Handle to our data     */
  1090.     menudatum **ourmhandle;        /* another Handle to our data     */
  1091.     itemdatum **items,**tempitems;    /* a Handle to the Item     */
  1092.     int lastid, lastitem;
  1093.     
  1094.     /* get the Handle to menu named 'name' */
  1095.     if ((ourmhandle = getourmenuhandle (name)) == 0L) {
  1096.     
  1097.         /* make a new menu entry by finding the end of the list */
  1098.         here = simplemenus;
  1099.         HLock (here);
  1100.         while ((**here).next) {
  1101.             temp = here;
  1102.             here = (menudatum **)(**here).next;
  1103.             HUnlock (temp);
  1104.             HLock (here);
  1105.         }
  1106.             
  1107.         /* make a structure for our new entry */
  1108.         lastid = (**here).menuId;
  1109.         (**here).next = (Ptr)NewHandle ( (long)sizeof(menudatum));
  1110.         temp = here;
  1111.         here = (menudatum **)(**here).next;
  1112.         HUnlock (temp);
  1113.         HLock (here);
  1114.  
  1115.         strcpy ( (**here).menuname, name);
  1116.         (**here).menuId = ++lastid;
  1117.         (**here).next = (Ptr) 0L;
  1118.         
  1119.         /* make a new Item structure */
  1120.         (**here).itemlist = (itemdatum **)NewHandle ( 
  1121.             (long)sizeof(itemdatum));
  1122.             
  1123.         /* make a new menu entry for the Macintosh */
  1124.         ctop (name);
  1125.         (**here).menuhand = NewMenu (lastid, name);
  1126.         ptoc (name);
  1127.         items = (**here).itemlist;
  1128.  
  1129.         HLock (items);
  1130.         strcpy ((**items).itemname, Item);
  1131.         (**items).itemno = 1;
  1132.         (**items).menuId = lastid;
  1133.         (**items).menuhand = (**here).menuhand;
  1134.         (**items).menurun = (ProcPtr) 0L;
  1135.         (**items).next = 0L;
  1136.         HUnlock (items);
  1137.         
  1138.         /* install and display the menu */
  1139.         ctop (Item);
  1140.         AppendMenu ((**here).menuhand, Item);
  1141.         ptoc (Item);
  1142.         InsertMenu ((**here).menuhand,0);
  1143.         HUnlock (here);
  1144.  
  1145.         setitems (items, routine);
  1146.         DrawMenuBar();
  1147.         return(TRUE);
  1148.     }
  1149.     else {
  1150.         HLock (ourmhandle);
  1151.  
  1152.         if (strlen(Item) == 0) {
  1153.           /* then adjust main menu */
  1154.           setitems( 0L - (long) ((**ourmhandle).menuhand), routine);
  1155.           return(FALSE);
  1156.         }
  1157.  
  1158.         /* see if Item is in list */
  1159.         items = (**ourmhandle).itemlist;
  1160.         HLock (items);
  1161.  
  1162.         while ( strcmp(Item,(**items).itemname) && (**items).next) {
  1163.             tempitems = items;
  1164.             items = (itemdatum **)(**items).next;
  1165.             HUnlock (tempitems);
  1166.             HLock (items);
  1167.         }
  1168.         if (strcmp(Item,(**items).itemname) ==0) {
  1169.             setitems( items, routine);
  1170.             return(FALSE);
  1171.         }
  1172.         else {
  1173.             /* make new Item entry */
  1174.             lastitem = (**items).itemno;
  1175.             (**items).next =(Ptr)NewHandle((long)sizeof(itemdatum));
  1176.             tempitems = items;
  1177.             items = (itemdatum **)(**items).next;
  1178.             HUnlock (tempitems);
  1179.             HLock (items);
  1180.  
  1181.             strcpy ((**items).itemname, Item);
  1182.             (**items).itemno = ++lastitem;
  1183.             (**items).menuId = (**ourmhandle).menuId;
  1184.             (**items).menuhand = (**ourmhandle).menuhand;
  1185.             (**items).menurun = (ProcPtr) 0L;
  1186.             (**items).next = 0L;
  1187.             HUnlock (items);
  1188.  
  1189.             /* and install the Item in the menu bar */
  1190.             ctop (Item);
  1191.             AppendMenu ((**ourmhandle).menuhand,Item);
  1192.             ptoc (Item);
  1193.             HUnlock (ourmhandle);
  1194.             setitems (items, routine);
  1195.             return(TRUE);
  1196.         }
  1197.     }
  1198. }
  1199.  
  1200. /* Given a menu name, return the real menu Handle as used by most
  1201.    of the Macintosh toolbox menu manager routines.
  1202. */
  1203.  
  1204. MenuHandle mhand (name)            /* find MenuHandle        */
  1205. char *name;                /* given name of menu         */
  1206. {
  1207.     menudatum    **menu;    
  1208.     MenuHandle    temp;        /* a Handle to our data     */
  1209.  
  1210.     menu = getourmenuhandle(name);
  1211.     if ( menu ) {
  1212.         HLock (menu);
  1213.         temp = (**menu).menuhand;
  1214.         HUnlock (menu);
  1215.         return ( temp );    /* return menu Handle         */
  1216.     } else
  1217.         return ( (MenuHandle) 0 );    
  1218. }
  1219.  
  1220.     
  1221. /*  Call this routine if you want these SimpleTools defined quiting    */
  1222. /*  procedures.  You may just install your own instead.     The time to    */
  1223. /*  call this is after you have installed all your other "File" items.    */
  1224. /*  By calling this last, you will place Transfer and Quit on the end    */
  1225. /*  of the menu list.                            */
  1226.  
  1227. simplequits ()
  1228. {
  1229.     menu ("File", "-", itemdisable);
  1230.     
  1231.     #ifndef LIGHTSPEED
  1232.     menu ("File", "Transfer.../T", gottrans);
  1233.     #endif
  1234.     
  1235.     menu ("File", "Quit/Q", gotquit);
  1236. }
  1237.  
  1238. /* Given a window's name, return its window pointer so that other
  1239.    Macintosh Window Manager routines can be called for that window. */
  1240.  
  1241. WindowPtr windowpoint(name)        /* get window pointer         */
  1242. char *name;                /* given window's name         */
  1243. {
  1244.     winddatum **wind, **tempwind;    /* Handle to our window data     */
  1245.     WindowPtr    temp;
  1246.  
  1247.     if (firstwind) return ((WindowPtr)0); 
  1248.     wind = simplewinds;        /* look for the named window     */
  1249.     HLock (wind);
  1250.  
  1251.     while ( strcmp ((**wind).windname, name) && (**wind).next) {
  1252.         tempwind = wind;
  1253.         wind = (winddatum **) (**wind).next;
  1254.         HUnlock (tempwind);
  1255.         HLock (wind);
  1256.     }
  1257.     if ( strcmp ((**wind).windname, name) ==0) {
  1258.         temp = (**wind).wptr;
  1259.         HUnlock (wind);
  1260.         return ( temp );    /* return pointer        */
  1261.     } else {
  1262.         HUnlock (wind);
  1263.         return ( (WindowPtr) 0);/* or zero if it wasn't found    */
  1264.     }
  1265. }
  1266.  
  1267. /* This routine installs a new window onto the screen.  It also gives
  1268.    that window an Item in the Window menu.  This routine is also used
  1269.    to modify a window's associated routines.  The x,y positions are the
  1270.    top left and bottom right corners of where the window should originally
  1271.    be placed.  The coordinates are never used when this routine is called
  1272.    to update an already existing window.  But the spaces must be filled,
  1273.    so you can use zeros if you want.  Once the window has been displayed in
  1274.    its original position, the user has complete control of its size and
  1275.    placement with the mouse.
  1276.    
  1277.    YOU MUST ASSIGN PROCEDURES TO BE CALLED WHEN SIMPLETOOLS DETECTS THAT
  1278.    THIS WINDOW IS BECOMMING ACTIVE, DEACTIVATING, NEEDS UPDATING, OR
  1279.    THE MOUSE HAS BEEN PRESSED IN ITS CONTENT.  JUST LIKE THE MENU PROCEDURE,
  1280.    THESE PROCEDURES ARE PASSED SOME ARGUMENTS.  YOU DO NOT HAVE TO 
  1281.    DECLARE THESE IF YOU DON'T WHAT TO USE THEM.  IF YOU USE THE ARGUMENTS,
  1282.    YOU WOULD DECLAR THESE PROCEDURES AS FOLLOWS:
  1283.    
  1284.        my_activate (windp, event)    same as my_update
  1285.     my_deactivate (windp, event)    same as my_update
  1286.     
  1287.     my_update (windp, event)
  1288.     WindowPtr     windp;        the window being acted upon
  1289.     EventRecord     *event;        the current event record
  1290.     {
  1291.         ...
  1292.     }
  1293.     
  1294.     my_inContent (x, y, windp, event)
  1295.     int         x, y;        mouse position in local coords
  1296.     WindowPtr     windp;        like above
  1297.     EventRecord     *event;        like above
  1298.     {
  1299.         ...
  1300.     }
  1301. */
  1302.  
  1303. window(name, xtop, ytop, xbot, ybot, a, d, u, c)
  1304. char *name;            /* window's name             */
  1305. int xtop, ytop, xbot, ybot;    /* position if this is a new window     */
  1306. ProcPtr a, d, u, c;        /* activate, deactivate, update, and     */
  1307. {                /*  content procedures          */
  1308.     winddatum **wind, **temp;/* Handle to our window data         */
  1309.     winddatum **newentry;    /* another Handle             */
  1310.     Rect newplace;        /* rectable for the window's placement    */
  1311.  
  1312.     if (a == (ProcPtr) 0)
  1313.         a = (ProcPtr) stnop;
  1314.     if (d == (ProcPtr) 0)
  1315.         d = (ProcPtr) stnop;
  1316.     if (u == (ProcPtr) 0)
  1317.         u = (ProcPtr) stnop;
  1318.     if (c == (ProcPtr) 0)
  1319.         c = (ProcPtr) stnop;
  1320.     if ( !firstwind ) {
  1321.  
  1322.         /* see if window is in the list */
  1323.         wind = simplewinds;
  1324.         HLock (wind);
  1325.  
  1326.         while ( strcmp ((**wind).windname, name) && (**wind).next) {
  1327.             temp = wind;
  1328.             wind = (winddatum **) (**wind).next;
  1329.             HUnlock (temp);
  1330.             HLock (wind);
  1331.         }
  1332.         if ( strcmp ((**wind).windname, name) ==0) {
  1333.  
  1334.             /* reset the found window's parameters */
  1335.             (**wind).wact = (ProcPtr) a;
  1336.             (**wind).wdeact = (ProcPtr) d;
  1337.             (**wind).wupdate = (ProcPtr) u;
  1338.             (**wind).wcontent = (ProcPtr) c;
  1339.             SetPort ( (**wind).wptr);        
  1340.             HUnlock (wind);
  1341.  
  1342.             return(FALSE);
  1343.         }
  1344.     }
  1345.  
  1346.     /* make a new window entry */
  1347.     newentry = (winddatum **)NewHandle ( (long) sizeof (winddatum));
  1348.     if (firstwind)
  1349.         simplewinds = newentry;
  1350.     else
  1351.         (**wind).next = (Ptr) newentry;
  1352.     firstwind = 0;
  1353.     HUnlock (wind);
  1354.     HLock (newentry);
  1355.  
  1356.     strcpy ((**newentry).windname, name);
  1357.     SetRect (&newplace, xtop, ytop, xbot, ybot);
  1358.     if (EmptyRect (&newplace)) 
  1359.         SetRect (&newplace, 10, 42, 500, 330);
  1360.     ctop (name);
  1361.     (**newentry).wptr = NewWindow (0L, &newplace, name, show_new_window, 
  1362.         wprocid, -1L, dogoaway, newentry);
  1363.     ptoc (name);
  1364.     (**newentry).wact = (ProcPtr) a;
  1365.     (**newentry).wdeact = (ProcPtr) d;
  1366.     (**newentry).wupdate = (ProcPtr) u;
  1367.     (**newentry).wcontent = (ProcPtr) c;
  1368.     (**newentry).next = (Ptr) 0;
  1369.     if (windmenu)
  1370.         menu ("Windows", name, showawindow); 
  1371.     SetPort ( (**newentry).wptr);        
  1372.     HUnlock (newentry);
  1373.  
  1374.     return(TRUE);
  1375. }
  1376.  
  1377. withwindow(name)            /* set output to window by name    */
  1378. char *name;                /* give it the window's name     */
  1379. {                    /* returns if window exists    */
  1380.     winddatum **wind, **temp;
  1381.     wind = simplewinds;
  1382.     if (firstwind) return(FALSE);    /* search for the window's name */
  1383.  
  1384.     HLock (wind);
  1385.     while ( strcmp ((**wind).windname, name) && (**wind).next) {
  1386.         temp = wind;
  1387.         wind = (winddatum **) (**wind).next;
  1388.         HUnlock (temp);
  1389.         HLock (wind);
  1390.     }
  1391.     if ( strcmp ((**wind).windname, name) ==0) {
  1392.         SetPort ( (**wind).wptr);    /* set output to it     */
  1393.         HUnlock (wind);
  1394.         return(TRUE);
  1395.     } else {
  1396.         HUnlock (wind);
  1397.         return(FALSE);
  1398.     }
  1399. }
  1400.   
  1401. /* This run procedure is used to install routines to be occasionally
  1402.    run.  The routine will be run once for each call to simpleevents()
  1403.    which is done repeatedly by runsimpletools().
  1404.    
  1405.    EACH ROUTINE INSERTED INTO THE RUN LIST IS RUN MULTIPLE TIMES UNTIL
  1406.    IT IS REMOVED BY CALLING STOP.  THE ROUTINE IS CALLED WITH A SINGLE
  1407.    ARGUMENT, A POINTER TO THE EVENT JUST RETURNED BY GETNEXTEVENT() AND
  1408.    BEFORE SIMPLETOOLS PROCESSES IT.
  1409. */
  1410.  
  1411. run(routine)            /* install a run procedure     */
  1412. ProcPtr routine;        /* give it the procedure     */
  1413. {                /* return TRUE if successful     */
  1414.     int i;
  1415.     i = 0;            /* add it to the end of the list */
  1416.     while ( simpleruns[i] != (ProcPtr) 0L) i++;
  1417.     if (i < maxsruns) {
  1418.         simpleruns[i] = routine;
  1419.         simpleruns[i+1] = (ProcPtr) 0L;
  1420.         return(TRUE);
  1421.     } else
  1422.         return(FALSE);
  1423. }
  1424.  
  1425. /* This routine removes a procedure from the list of run procedures */
  1426.  
  1427. stop(routine)            /* stop a procedure from running*/
  1428. ProcPtr routine;        /* give the procedure         */
  1429. {                /* return TRUE if successful     */
  1430.     int i = 0;
  1431.     while ( (simpleruns[i] != routine) && simpleruns[i])  i++;
  1432.     if (simpleruns[i]) {
  1433.         while ( simpleruns[i] != (ProcPtr)0 ) {
  1434.             simpleruns[i] = simpleruns[i+1];
  1435.             i++;
  1436.         }
  1437.         return(TRUE);
  1438.     } else {
  1439.         return(FALSE);
  1440.     }
  1441. }
  1442.  
  1443. void home ()            /* text-based home of the pen with
  1444.                    the window being erased.        */
  1445. {
  1446.     GrafPtr    port;
  1447.     GetPort (&port);
  1448.     EraseRect (&(port->portRect));
  1449.     stgotoxy (1, 1);
  1450. }
  1451.  
  1452. stgotoxy (x, y)                /* goto text position x, y    */
  1453. int x, y;    
  1454. {
  1455.     Point        pt;
  1456.     int        newx, newy;
  1457.     FontInfo    font;
  1458.   
  1459.     GetFontInfo (&font);
  1460.     GetPen (&pt);
  1461.     #ifdef MEGAMAX
  1462.     if (x < 0) 
  1463.         newx = pt.a.h;
  1464.     else
  1465.         newx = font.widMax * (x);
  1466.     if (y < 0)
  1467.         newy = pt.a.v;
  1468.     #else
  1469.     if (x < 0) 
  1470.         newx = pt.h;
  1471.     else
  1472.         newx = font.widMax * (x);
  1473.     if (y < 0)
  1474.         newy = pt.v;
  1475.     #endif
  1476.     else
  1477.         newy = (font.ascent + font.descent + font.leading) * (y+1);
  1478.     MoveTo (newx, newy);
  1479. }
  1480.  
  1481. /* The getline procedure is to be called when you want to simply get a Line
  1482.    of text from the user at the current pen position on the screen.  You
  1483.    will probably preceed this with a call to stgotoxy(x,y).  You would call
  1484.    it like:    
  1485.            getline ("Erik", name);
  1486.         
  1487.    where name is a character array.  This works MUCH better than scanf()
  1488.    or gets() since it uses the Macintosh TextEdit routines to allow the
  1489.    user to edit the Line being input.
  1490.    
  1491.    Getline is very "modal" and no other events are handled while the
  1492.    user is expected to enter the Line.  Getline returns ONLY when the
  1493.    user presses <RETURN>.  
  1494.    
  1495.    Routines scheduled to run by the run() routine are called.  Make sure
  1496.    your run routines don't strip all <RETURNS> from the event record
  1497.    they get or getline will never stop.
  1498. */
  1499.    
  1500. getline (dfault, destination)        /* using TE, get a Line        */
  1501. char *dfault, *destination;        /* default string, dest     */
  1502. {
  1503.     TEHandle         hte;
  1504.     Rect            destRect;
  1505.     Point            pen,pt;
  1506.     FontInfo        FInfo;
  1507.     int            done, mask, code, in_already, nextcap;
  1508.     GrafPtr            port, window;
  1509.     EventRecord        event;
  1510.     char            key;
  1511.     CursHandle        c;
  1512.     
  1513.     GetPort (&port);        /* Calculate Rect for TE    */
  1514.     if (port != FrontWindow())  SelectWindow (port);
  1515.     GetPen (&pen);
  1516.     GetFontInfo (&FInfo);
  1517.     #ifdef MEGAMAX
  1518.         SetRect (&destRect, pen.a.h, pen.a.v - FInfo.ascent,
  1519.             1000, pen.a.v + FInfo.descent);
  1520.     #else
  1521.         SetRect (&destRect, pen.h - 1, pen.v - FInfo.ascent,
  1522.             1000, pen.v + FInfo.descent);
  1523.     #endif
  1524.     EraseRect (&destRect);
  1525.     hte = TENew (&destRect, &destRect);    
  1526.     TESetText (dfault, (long)strlen(dfault), hte);
  1527.     TEActivate (hte);
  1528.     TEUpdate (&destRect, hte);
  1529.     mask = mDownMask + keyDownMask + autoKeyMask + mUpMask;
  1530.     done = FALSE;
  1531.     #ifdef MEGAMAX
  1532.       c = GetCursor (ibeamcursor);
  1533.     #else
  1534.       c = GetCursor (iBeamCursor);
  1535.     #endif
  1536.     in_already = FALSE;
  1537.     nextcap = getlinecaps;
  1538.     do {                /* "modal" loop until <cr>    */
  1539.         SystemTask ();
  1540.         TEIdle (hte);
  1541.         
  1542.         GetNextEvent (mask, &event);
  1543.         runruns (&event);
  1544.         GetMouse (&pt);        /* use I beam in TE        */
  1545.         if (PtInRect (ZZ(pt), &destRect)) {
  1546.           if ( ! in_already )  {
  1547.              SetCursor (*c);
  1548.              in_already = TRUE;
  1549.           }
  1550.         } else {
  1551.           if ( in_already ) {
  1552.               InitCursor ();
  1553.               in_already = FALSE;
  1554.           }
  1555.         }
  1556.         switch (event.what) {
  1557.             case mouseDown:
  1558.             code = FindWindow (ZZ(event.where),&window);
  1559.             if ((code == inContent) && (window == port)) {
  1560.                GlobalToLocal (&event.where);
  1561.                 if (PtInRect(ZZ(event.where),&destRect))
  1562.                     TEClick (ZZ(event.where), 0, hte);
  1563.                 else SysBeep (1);
  1564.             } else SysBeep (20);
  1565.             break;
  1566.             case keyDown:
  1567.             case autoKey:
  1568.                 key = (char) (event.message & 0xFFL);
  1569.             if (nextcap && (key >= 'a') && (key <= 'z')) 
  1570.                 key -= ' ';
  1571.             nextcap = FALSE;
  1572.             if (key == ' ') nextcap = getlinecaps;
  1573.             if (key != '\r')  TEKey (key, hte);
  1574.             else  done = TRUE;
  1575.             break;
  1576.         }
  1577.     } while (!done);
  1578.     TEDeactivate (hte);
  1579.     
  1580.     /* For LIGHTSPEED, use a lowercase te and upper case L in    */
  1581.     /* TElength.  Megamax conversion utility does this wrong too.    */
  1582.     
  1583.     strncpy (destination, *TEGetText(hte), (*hte)->teLength);
  1584.     destination[(*hte)->teLength] = 0;
  1585.  
  1586.     TEDispose (hte);
  1587.         InitCursor ();
  1588. }
  1589.  
  1590. /*  Use prompt when you want a tiny window to pop up to ask the user
  1591.     a question.  The question is drawn and a TextEdit box is provided
  1592.     to get the answer.  Whatever the user leaves in the answer box
  1593.     is returned in answer.  Two buttons are also displayed:  OK and
  1594.     CANCEL.  Prompt returns TRUE or FALSE depending on which Button was
  1595.     pressed.
  1596. */
  1597.  
  1598. prompt ( question, answer)        /* dialog box question/answer */
  1599. char *question;
  1600. char *answer;
  1601. {
  1602.     return (stdialog (question, answer, 1));
  1603. }
  1604.  
  1605. /* Message is just like prompt except no answer box is displayed.  An
  1606.    OK and CANCEL Button works just like prompt.
  1607. */
  1608.  
  1609. message ( message )            /* dialog box message         */
  1610. char *message;
  1611. {
  1612.     return (stdialog (message, message, 2));
  1613. }
  1614.   
  1615. /*  This routine is a simpler whay to call the toolbox SFGetFile()
  1616.     routine.  Simple call this like:
  1617.     
  1618.             getfile ("TEXT", filename)
  1619.         
  1620.     where filename is a character array.  Replace TEXT with whatever
  1621.     file type you desire.  The file manager's working directory is set
  1622.     correctly so that a subsequent open() call with filename will work.
  1623. */
  1624.  
  1625. getfile (ftype, reply)
  1626. char ftype[];
  1627. char reply[];
  1628. {
  1629.     Point where;
  1630.     SFReply frommac;
  1631.     
  1632.     #ifdef MEGAMAX
  1633.       where.a.h = 75; where.a.v = 50;
  1634.     #else
  1635.       where.h = 75; where.v = 50;
  1636.     #endif
  1637.     if (strlen(ftype) != 4)
  1638.       SFGetFile (ZZ(where), NULL, NULL, -1, NULL, NULL, &frommac);
  1639.     else
  1640.       SFGetFile (ZZ(where), NULL, NULL, 1, ftype, 0L, &frommac);
  1641.     if (frommac.good) {
  1642.       SetVol ("", frommac.vRefNum);
  1643.       strcpy (reply, frommac.fName);
  1644.       return (TRUE);
  1645.     }
  1646.     else return (FALSE);
  1647. }
  1648.  
  1649. /* This is like getfile, but may get a new file name from the user.
  1650.    Origname is the default you want to present to the user.
  1651. */
  1652.  
  1653. putfile (origname,reply)
  1654. char *origname;
  1655. SFReply *reply;
  1656. {
  1657.     Point where;
  1658.     SFReply frommac;
  1659.     
  1660.     #ifdef MEGAMAX
  1661.       where.a.h = 75; where.a.v = 50;
  1662.     #else
  1663.       where.h = 75; where.v = 50;
  1664.     #endif
  1665.     SFPutFile (ZZ(where), "", origname, 0L, &frommac);
  1666.     if (frommac.good) {
  1667.       SetVol ("", frommac.vRefNum);
  1668.       strcpy (reply, frommac.fName);
  1669.       return (TRUE);
  1670.     }
  1671.     return (FALSE);
  1672. }
  1673.  
  1674. /* This routine initializes SimpleTools and MUST be called before    */
  1675. /* most of the other SimpleTools routines are called.            */
  1676. /* The passed about string is the menu Item name to appear just under    */
  1677. /* the Apple menu.  This will be disabled and can be enabled using    */
  1678. /* a menu() call.  This routine also initializes the Macintosh         */
  1679. /* for application execution and desk accessory processing.        */
  1680.  
  1681. simpletools(about)    /* to be called at the beginning of program     */
  1682. char *about;
  1683. {
  1684.     #ifdef MEGAMAX
  1685.       maxapplzone();    /* allow maximum heap expansion     */
  1686.     #else
  1687.       MaxApplZone();
  1688.     #endif
  1689.     FlushEvents (everyEvent,0);  /* ignore left over events     */
  1690.     InitGraf (&thePort);    /* initialize the screen         */
  1691.     InitFonts();        
  1692.     InitWindows();
  1693.     InitMenus();
  1694.     InitCursor();        /* make the arrow Cursor         */
  1695.     TEInit();
  1696.     InitDialogs(gotquit);
  1697.     snewrom = havenewrom();
  1698.     
  1699.     /* Ugh.  For LightSpeed use a lower case d in DocumentProc.    */
  1700.     /* Megamax conversion utility is at fault here.            */
  1701.     
  1702.     wprocid = documentProc;
  1703.     if (snewrom) wprocid = zoomproc;
  1704.     SetRect ( &sizerect, 20, 50, 250, 330);
  1705.     simpleruns[0] = (ProcPtr) 0;  /* empty the run list         */
  1706.  
  1707.     /* These are the bounds we are allowed to size a window or
  1708.        Move a window to.  
  1709.     */
  1710.  
  1711.     swholescreen = dragrect = thePort -> portRect;
  1712.     InsetRect (&dragrect, 4, 4);
  1713.     SetRect ( &sizerect, 20, 20, 2048, 700);
  1714.     firstwind = 1;            /* empty window table        */
  1715.     keydownproc = (ProcPtr) stnop;    /* default key hit procedures     */
  1716.     autokeyproc = (ProcPtr) stnop;
  1717.     initsmenus(about);        /* install the menus         */
  1718. }
  1719.  
  1720. simpleevents()                /* to be called in the main loop */
  1721. {
  1722.     EventRecord newevent;
  1723.     winddatum **thewdatum;
  1724.     SystemTask();            /* Do the system D.A. etc. stuff */
  1725.     HiliteMenu(0);
  1726.     GetNextEvent(everyEvent, &newevent);
  1727.     runruns(&newevent);        /* Do our run procedures     */
  1728.     switch (newevent.what) {
  1729.         case mouseDown:
  1730.         domousedown(&newevent); break;
  1731.         case keyDown: 
  1732.         if (newevent.modifiers & cmdKey)
  1733.             docommand(MenuKey((char)(newevent.message & 0xffL)),
  1734.                 &newevent);
  1735.         (*(keydownproc))(&newevent);
  1736.          break;
  1737.         case autoKey: 
  1738.         if (newevent.modifiers & cmdKey)
  1739.             docommand(MenuKey((char)(newevent.message & 0xffL)),
  1740.                 &newevent);
  1741.         (*(autokeyproc))(&newevent);
  1742.         break;
  1743.         case activateEvt: 
  1744.         thewdatum = wdatum(newevent.message);
  1745.         if (thewdatum) {
  1746.             SetPort(newevent.message);
  1747.             HLock (thewdatum);
  1748.             if (newevent.modifiers & 1) {
  1749.  
  1750.                 (*((**thewdatum).wact))(newevent.message, 
  1751.                     &newevent);
  1752.             } else {
  1753.                 (*((**thewdatum).wdeact))(newevent.message,
  1754.                     &newevent);
  1755.             }
  1756.             HUnlock (thewdatum);
  1757.         }
  1758.         break;
  1759.         case updateEvt:
  1760.         thewdatum = wdatum(newevent.message);
  1761.         if (thewdatum) {
  1762.             SetPort (newevent.message);
  1763.             BeginUpdate (newevent.message);
  1764.             HLock (thewdatum);
  1765.             (*((**thewdatum).wupdate))(newevent.message,
  1766.                 &newevent);
  1767.             HUnlock (thewdatum);
  1768.             EndUpdate (newevent.message);
  1769.         }
  1770.         break;
  1771.     }
  1772. }
  1773.  
  1774. runsimpletools ()
  1775. {
  1776.     for (;;) simpleevents();
  1777. }
  1778.  
  1779.